
package uestc.bitman.edxapp;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import uestc.bitman.edxapp.chapter.CourseChapter;
import uestc.bitman.edxapp.courselist.Course;
import uestc.bitman.edxapp.tools.ResponseStringTools;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Handler;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author hackeris
 * @category An Edx User
 */
public class EdxStudentUser {

    private String mUserEmail;

    private String mUserPassword;

    /**
     * We need this to ensure the cookie is the same all the time.
     */
    private HttpClient mHttpClient;

    private boolean mLoginStatus, mSavedLoginStatus;

    /**
     * @category Constructor
     * @param email User email
     * @param password User password
     */
    public EdxStudentUser(String email, String password) {
        mUserEmail = email;
        mUserPassword = password;
        HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams,
                EdxAppConfigurations.HTTP_REQUEST_TIMEOUT);
        HttpConnectionParams.setSoTimeout(httpParams,
                EdxAppConfigurations.HTTP_DATA_WAITING_TIMEOUT);
        mHttpClient = new DefaultHttpClient(httpParams);
        mLoginStatus = mSavedLoginStatus = false;
    }

    public void savePassword(Context context) {
        SharedPreferences preferences = context.getSharedPreferences("user_info",
                Context.MODE_PRIVATE);
        Editor editor = preferences.edit();
        editor.putString("user_email", mUserEmail);
        editor.putString("user_pass", mUserPassword);
        editor.putBoolean("login_status", mSavedLoginStatus);
        editor.commit();
    }

    public void loadSavedData(Context context) {
        SharedPreferences preferences = context.getSharedPreferences("user_info",
                Context.MODE_PRIVATE);
        mUserEmail = preferences.getString("user_email", "");
        mUserPassword = preferences.getString("user_pass", "");
        mSavedLoginStatus = preferences.getBoolean("login_status", false);
    }

    public String getUserEmail() {
        return mUserEmail;
    }

    public String getUserPassword() {
        return mUserPassword;
    }

    public void setUserEmail(String email) {
        mUserEmail = email;
    }

    public void setUserPassword(String password) {
        mUserPassword = password;
    }

    private void setLoginStatus(boolean status) {
        mLoginStatus = mSavedLoginStatus = status;
    }

    public void saveLoginStatus(Context context) {
        SharedPreferences preferences = context.getSharedPreferences("user_info",
                Context.MODE_PRIVATE);
        Editor editor = preferences.edit();
        editor.putBoolean("login_status", mLoginStatus);
        editor.commit();
    }

    public boolean getSavedLoginStatus(Context context) {
        SharedPreferences preferences = context.getSharedPreferences("user_info",
                Context.MODE_PRIVATE);
        return preferences.getBoolean("login_status", false);
    }

    public void logOut() {
        mSavedLoginStatus = mLoginStatus = false;
    }

    public boolean isLogin(){
        return mLoginStatus;
    }
    /**
     * @category Log in
     * @return true if login sucess
     */
    public boolean login(Handler timeoutHandler) {

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        NameValuePair usrEmail = new BasicNameValuePair(EdxAppConfigurations.USER_EMAIL_KEY_NAME,
                mUserEmail);
        NameValuePair usrPass = new BasicNameValuePair(EdxAppConfigurations.USER_PASSWORD_KEY_NAME,
                mUserPassword);
        NameValuePair remember = new BasicNameValuePair(
                EdxAppConfigurations.USER_REMEMBER_KEY_NAME, "false");
        params.add(usrEmail);
        params.add(usrPass);
        params.add(remember);

        HttpResponse response = sendPost(
                EdxAppConfigurations.createRequestUrl(EdxAppConfigurations.LOGIN_URL), params);
        if (response == null) {
            if (timeoutHandler != null) {
                timeoutHandler.sendEmptyMessage(0);
                setLoginStatus(false);
                return false;
            }
        }
        String result = "";
        try {
            result = EntityUtils.toString(response.getEntity(), "utf-8");
            JSONTokener jsonParser = new JSONTokener(result);
            JSONObject loginResult = (JSONObject) jsonParser.nextValue();
            boolean bResult = loginResult.getBoolean("success");
            setLoginStatus(bResult);
            return bResult;
        } catch (Exception e) {
            e.printStackTrace();
        }
        setLoginStatus(false);
        return false;
    }

    /**
     * @category Get the course list of user in json format
     * @return The json of course list
     */
    private String getCourseListJson() {
        HttpResponse response = sendGet(
                EdxAppConfigurations.createRequestUrl(EdxAppConfigurations.APP_DASHBOARD_URL), "");
        try {
            return ResponseStringTools.preProcJson(EntityUtils.toString(response.getEntity(),
                    "uft-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * @category Get the course list
     * @return An ArrayList of Course
     */
    public List<Course> getCourseList() {
        String result = getCourseListJson();
        if (result.equals("")) {
            return null;
        }
        JSONObject response = null;
        JSONArray array = new JSONArray();
        try {
            response = new JSONObject(result);
            array = response.getJSONArray("courses");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Gson gson = new Gson();
        String jsonArrayString = array.toString();
        List<Course> courseList = gson.fromJson(jsonArrayString.toString(),
                new TypeToken<List<Course>>() {
                }.getType());
        return courseList;
    }

    /**
     * @category Get all the courses in json string
     * @return The json of all courses
     */
    private String getCoursesJson() {

        HttpResponse response = sendGet(
                EdxAppConfigurations.createRequestUrl(EdxAppConfigurations.APP_COURSES_LIST), "");
        try {
            return ResponseStringTools.preProcJson(EntityUtils.toString(response.getEntity(),
                    "uft-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public List<Course> getCourses() {

        String json = getCoursesJson();
        List<Course> courses = new ArrayList<Course>();

        if (json.equals("")) {
            return courses;
        }

        JSONObject response = null;
        JSONArray array = new JSONArray();

        try {
            response = new JSONObject(json);
            array = response.getJSONArray("courses");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Gson gson = new Gson();
        String jsonArrayString = array.toString();

        courses = gson.fromJson(jsonArrayString.toString(), new TypeToken<List<Course>>() {
        }.getType());

        return courses;
    }

    /**
     * @param subUrl The url of the course info page
     * @return The course info content in html
     */
    public String getCourseInfoHtml(String subUrl) {
        HttpResponse response = sendGet(EdxAppConfigurations.createRequestUrl(subUrl), "");
        try {
            return ResponseStringTools.preProcXml(EntityUtils.toString(response.getEntity(),
                    "uft-8"));
        } catch (Exception e) {
            // e.printStackTrace();
        }
        return "";
    }

    /**
     * @category To get the category of a special course in json
     * @param courseware The url of courseware main page
     * @return a String contains the content of course category in json
     */
    private String getCourseChaptersJson(String courseware) {
        HttpResponse response = sendGet(EdxAppConfigurations.createRequestUrl(courseware), "");
        int requestCode = response.getStatusLine().getStatusCode();
        if (requestCode == 200) {
            try {
                String result = ResponseStringTools.preProcJson(EntityUtils.toString(
                        response.getEntity(), "utf-8"));
                return result;
            } catch (Exception e) {
                // e.printStackTrace();
            }
        }
        return "";
    }

    /**
     * @category To get the category of a special course
     * @param courseware See the getCourseChaptersJson
     * @return An ArrayList of the chapters
     */
    public List<CourseChapter> getCourseChapters(String courseware) {
        String result = getCourseChaptersJson(courseware);
        JSONObject response = null;
        JSONArray jsonArray = null;
        try {
            response = new JSONObject(result);
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
        try {
            if (response.has("chapters")) {
                jsonArray = response.getJSONArray("chapters");
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }

        Gson gson = new Gson();
        List<CourseChapter> chapterList = gson.fromJson(jsonArray.toString(),
                new TypeToken<List<CourseChapter>>() {
                }.getType());
        return chapterList;
    }

    /**
     * @category Get the XML content of a specified section
     * @param subUrl The url of a course section
     * @return a String contains the content of a specified section
     */
    public String getCourseSectionContentXml(String subUrl) {
        HttpResponse response = sendGet(EdxAppConfigurations.createRequestUrl(subUrl), "");
        if (response == null) {
            return "";
        }
        int requestCode = response.getStatusLine().getStatusCode();
        if (requestCode == 200) {
            String result;
            try {
                result = ResponseStringTools.preProcXml(EntityUtils.toString(response.getEntity(),
                        "utf-8"));
                return result;
            } catch (Exception e) {
                // e.printStackTrace();
            }
        }

        return "";
    }

    public boolean changeEnrollment(String courseId, String action) {
        List<NameValuePair> params = new ArrayList<NameValuePair>();

        NameValuePair idValuePair = new BasicNameValuePair(
                EdxAppConfigurations.CHANGE_ENROLLMENT_COURSE_ID, courseId);
        NameValuePair actionValuePair = new BasicNameValuePair(
                EdxAppConfigurations.CHANGE_ENROLLMENT_ACTION, action);
        params.add(idValuePair);
        params.add(actionValuePair);
        HttpResponse response = sendPost(
                EdxAppConfigurations.createRequestUrl(EdxAppConfigurations.APP_CHANGE_ENROLL),
                params);
        int code = response.getStatusLine().getStatusCode();
        // Log.d("return code", code + "");
        return (code == 200);
    }

    /**
     * @category Send a post request
     * @param url The destination url
     * @param paramsList Params
     * @return The httpResponse
     */
    private HttpResponse sendPost(String url, List<NameValuePair> paramsList) {
        HttpPost postRequest = new HttpPost(url);
        BasicHttpParams httpParams = new BasicHttpParams();
        httpParams.setParameter("http.protocol.handle-redirects", false);
        postRequest.setParams(httpParams);
        try {
            postRequest.setEntity(new UrlEncodedFormEntity(paramsList, HTTP.UTF_8));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try {
            return mHttpClient.execute(postRequest);
        } catch (Exception e) {
            // e.printStackTrace();
        }
        return null;
    }

    /**
     * @category See the function sendPost()
     * @param url See the function sendPost()
     * @param params See the function sendPost()
     * @return See the function sendPost()
     */
    private HttpResponse sendGet(String url, String params) {
        HttpGet getRequest = new HttpGet(url + params);
        BasicHttpParams httpParams = new BasicHttpParams();
        httpParams.setParameter("http.protocol.handle-redirects", false);
        getRequest.setParams(httpParams);
        try {
            return mHttpClient.execute(getRequest);
        } catch (Exception e) {
            // e.printStackTrace();
        }
        return null;
    }
}
